/**
 * Copyright (C) 2010 - 2013 Harry Glasgow
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.jaden.ui.dialog;

import com.googlecode.jaden.common.config.ProjectConfiguration;
import com.googlecode.jaden.common.other.Utils;
import com.googlecode.jaden.ui.UiUtils;
import com.googlecode.jaden.ui.UI;
import static com.googlecode.jaden.ui.Constants.*;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.prefs.Preferences;

public class EditTrainingFilesDialog extends BaseDialog {

    private final UI ui;

    private final JTextField trainingFileNameField;

    private final JCheckBox useTrainingForValidationCB;
    private final JTextField validationFileNameField;
    private final JButton validationFileButton;
    private final SpinnerNumberModel validationPercentageSpinnerModel;
    private final JSpinner validationPercentageSpinner;

    private final JCheckBox useTrainingForTestingCB;
    private final JTextField testingFileNameField;
    private final JButton testingFileButton;
    private final SpinnerNumberModel testingPercentageSpinnerModel;
    private final JSpinner testingPercentageSpinner;

    private final SpinnerNumberModel firstLineSpinnerModel;

    private final JCheckBox scanToEndCB;
    private final SpinnerNumberModel lastLineSpinnerModel;
    private final JSpinner lastLineSpinner;

    private final JCheckBox coalesceDuplicateColumnSeparatorsCB;

    private final JRadioButton spaceDelimitRB;
    private final JRadioButton tabDelimitRB;
    private final JRadioButton otherDelimitRB;
    private final JTextField delimitField;

    private final JLabel validationPercentLabel;
    private final JLabel validationFileLabel;
    private final JLabel testingPercentLabel;
    private final JLabel testingFileLabel;

    private final JFileChooser chooser;

    private final JTextField decimalSeparatorField;

    private final JRadioButton otherThousandsSeparatorRB;
    private final JTextField thousandsSeparatorField;

    private final JRadioButton otherStringLimiterRB;
    private final JTextField stringLimiterField;

    private final JCheckBox randomizeDataCB;

    public EditTrainingFilesDialog(UI ui, Preferences preferences, ProjectConfiguration project) {
        super(ui, DIALOG_TRAINING_FILES_TITLE);
        this.ui = ui;

        chooser = new JFileChooser();
        ui.loadDataDirectory(chooser);

        trainingFileNameField = new JTextField(20);
        trainingFileNameField.setEditable(false);
        JButton trainingFileButton = new JButton("...");

        useTrainingForValidationCB = new JCheckBox(
                Utils.translate(LABEL_USE_TRAINING_FOR_VALIDATION_TEXT));
        validationFileNameField = new JTextField(20);
        validationFileNameField.setEditable(false);
        validationFileButton = new JButton("...");
        validationPercentageSpinnerModel = new SpinnerNumberModel(10, 1, 33, 1);
        validationPercentageSpinner = new JSpinner(validationPercentageSpinnerModel);

        useTrainingForTestingCB = new JCheckBox(
                Utils.translate(LABEL_USE_TRAINING_FOR_TESTING_TEXT));
        testingFileNameField = new JTextField(20);
        testingFileNameField.setEditable(false);
        testingFileButton = new JButton("...");
        testingPercentageSpinnerModel = new SpinnerNumberModel(10, 1, 33, 1);
        testingPercentageSpinner = new JSpinner(testingPercentageSpinnerModel);

        firstLineSpinnerModel = new SpinnerNumberModel(1, 1, 999, 1);
        JSpinner firstLineSpinner = new JSpinner(firstLineSpinnerModel);

        scanToEndCB = new JCheckBox(Utils.translate(LABEL_SCAN_TO_END_TEXT));
        lastLineSpinnerModel = new SpinnerNumberModel(1, 1, 999, 1);
        lastLineSpinner = new JSpinner(lastLineSpinnerModel);

        spaceDelimitRB = new JRadioButton(Utils.translate(LABEL_DELIMITER_SPACE_TEXT));
        tabDelimitRB = new JRadioButton(Utils.translate(LABEL_DELIMITER_TAB_TEXT));
        otherDelimitRB = new JRadioButton(Utils.translate(LABEL_DELIMITER_OTHER_TEXT));

        delimitField = new JTextField(1);

        ButtonGroup bg = new ButtonGroup();
        bg.add(spaceDelimitRB);
        bg.add(tabDelimitRB);
        bg.add(otherDelimitRB);

        JLabel trainingFileLabel = new JLabel(Utils.translate(LABEL_TRAINING_FILE_TEXT));
        validationPercentLabel = new JLabel(Utils.translate(LABEL_VALIDATION_PERCENT_TEXT));
        validationFileLabel = new JLabel(Utils.translate(LABEL_VALIDATION_FILE_TEXT));
        testingPercentLabel = new JLabel(Utils.translate(LABEL_TRAINING_PERCENT_TEXT));
        testingFileLabel = new JLabel(Utils.translate(LABEL_TESTING_FILE_TEXT));
        JLabel firstLineLabel = new JLabel(Utils.translate(LABEL_FIRST_LINE_TEXT));
        JLabel lastLineLabel = new JLabel(Utils.translate(LABEL_LAST_LINE_TEXT));
        JLabel columnSeparatorLabel = new JLabel(Utils.translate(LABEL_COLUMN_SEPARATOR_TEXT));

        coalesceDuplicateColumnSeparatorsCB = new JCheckBox(Utils.translate(LABEL_COALESCE_DUPLICATE_COLUMN_SEPARATORS_TEXT));

        JLabel decimalSeparatorLabel = new JLabel(Utils.translate(LABEL_DECIMAL_SEPARATOR_TEXT));
        decimalSeparatorField = new JTextField(1);

        JLabel thousandsSeparatorLabel = new JLabel(Utils.translate(LABEL_THOUSANDS_SEPARATOR_TEXT));
        JRadioButton noneThousandsSeparatorRB = new JRadioButton(Utils.translate(LABEL_NONE_TEXT));
        otherThousandsSeparatorRB = new JRadioButton(Utils.translate(LABEL_DELIMITER_OTHER_TEXT));
        thousandsSeparatorField = new JTextField(1);
        bg = new ButtonGroup();
        bg.add(noneThousandsSeparatorRB);
        bg.add(otherThousandsSeparatorRB);

        JLabel stringLimiterLabel = new JLabel(Utils.translate(LABEL_STRING_LIMITER_TEXT));
        JRadioButton noneStringLimiterRB = new JRadioButton(Utils.translate(LABEL_NONE_TEXT));
        otherStringLimiterRB = new JRadioButton(Utils.translate(LABEL_DELIMITER_OTHER_TEXT));
        stringLimiterField = new JTextField(1);
        bg = new ButtonGroup();
        bg.add(noneStringLimiterRB);
        bg.add(otherStringLimiterRB);

        UiUtils.enWidth(trainingFileLabel, validationFileLabel, testingFileLabel);
        UiUtils.enWidth(firstLineLabel, lastLineLabel);
        UiUtils.enWidth(validationPercentLabel, testingPercentLabel);
        UiUtils.enWidth(thousandsSeparatorLabel, stringLimiterLabel);

        randomizeDataCB = new JCheckBox(Utils.translate(LABEL_RANDOMIZE_DATA_TEXT));

        JPanel filesPanel = UiUtils.verticalList(
                UiUtils.horizontalList(trainingFileLabel, trainingFileNameField, trainingFileButton),
                UiUtils.horizontalList(useTrainingForValidationCB),
                UiUtils.horizontalList(validationFileLabel, validationFileNameField, validationFileButton),
                UiUtils.horizontalList(validationPercentLabel, validationPercentageSpinner),
                UiUtils.horizontalList(useTrainingForTestingCB),
                UiUtils.horizontalList(testingFileLabel, testingFileNameField, testingFileButton),
                UiUtils.horizontalList(testingPercentLabel, testingPercentageSpinner),
                UiUtils.horizontalList(randomizeDataCB)
        );

        JPanel fieldsPanel = UiUtils.verticalList(
                UiUtils.horizontalList(columnSeparatorLabel, spaceDelimitRB, tabDelimitRB, otherDelimitRB, delimitField),
                UiUtils.horizontalList(coalesceDuplicateColumnSeparatorsCB),
                UiUtils.horizontalList(firstLineLabel, firstLineSpinner),
                UiUtils.horizontalList(scanToEndCB),
                UiUtils.horizontalList(lastLineLabel, lastLineSpinner),
                UiUtils.horizontalList(decimalSeparatorLabel, decimalSeparatorField),
                UiUtils.horizontalList(thousandsSeparatorLabel, noneThousandsSeparatorRB, otherThousandsSeparatorRB, thousandsSeparatorField),
                UiUtils.horizontalList(stringLimiterLabel, noneStringLimiterRB, otherStringLimiterRB, stringLimiterField)
        );

        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.add(Utils.translate(LABEL_FILES_TEXT), UiUtils.horizontalList(filesPanel));
        tabbedPane.add(Utils.translate(LABEL_FIELDS_TEXT), UiUtils.horizontalList(fieldsPanel));
        setMainPanel(UiUtils.horizontalList(tabbedPane), preferences);

        trainingFileNameField.setText(project.getTrainingFilePath());
        useTrainingForValidationCB.setSelected(project.isValidationFromTrainingFile());
        validationFileNameField.setText(project.getValidationFilePath());
        validationPercentageSpinnerModel.setValue(project.getValidationDataPercentage());
        useTrainingForTestingCB.setSelected(project.isTestingFromTrainingFile());
        testingFileNameField.setText(project.getTestingFilePath());
        testingPercentageSpinnerModel.setValue(project.getTestingDataPercentage());
        firstLineSpinnerModel.setValue(project.getFirstLine());
        scanToEndCB.setSelected(project.isScanToEnd());
        lastLineSpinnerModel.setValue(project.getLastLine());
        decimalSeparatorField.setText(project.getDecimalSeparator());
        noneThousandsSeparatorRB.setSelected(!project.isUseThousandsSeparator());
        otherThousandsSeparatorRB.setSelected(project.isUseThousandsSeparator());
        thousandsSeparatorField.setText(project.getThousandsSeparator());
        noneStringLimiterRB.setSelected(!project.isUseStringLimiter());
        otherStringLimiterRB.setSelected(project.isUseStringLimiter());
        stringLimiterField.setText(project.getStringLimiter());
        randomizeDataCB.setSelected(project.isRandomizeData());
        coalesceDuplicateColumnSeparatorsCB.setSelected(project.isCoalesceDuplicateColumnSeparators());

        if (project.getColumnSeparator().equals(" ")) {
            spaceDelimitRB.setSelected(true);
        } else if (project.getColumnSeparator().equals("\t")) {
            tabDelimitRB.setSelected(true);
        } else {
            otherDelimitRB.setSelected(true);
            delimitField.setText(project.getColumnSeparator());
        }

        useTrainingForValidationCB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableTrainingForValidation();
            }
        });
        useTrainingForTestingCB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableTrainingForTesting();
            }
        });
        spaceDelimitRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableDelimiter();
            }
        });
        tabDelimitRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableDelimiter();
            }
        });
        otherDelimitRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableDelimiter();
            }
        });
        delimitField.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (delimitField.getText().length() > 1) {
                    delimitField.setText(delimitField.getText().substring(0, 1));
                }
            }
        });
        decimalSeparatorField.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (decimalSeparatorField.getText().length() > 1) {
                    decimalSeparatorField.setText(decimalSeparatorField.getText().substring(0, 1));
                }
            }
        });
        thousandsSeparatorField.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (thousandsSeparatorField.getText().length() > 1) {
                    thousandsSeparatorField.setText(thousandsSeparatorField.getText().substring(0, 1));
                }
            }
        });
        stringLimiterField.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (stringLimiterField.getText().length() > 1) {
                    stringLimiterField.setText(stringLimiterField.getText().substring(0, 1));
                }
            }
        });
        noneThousandsSeparatorRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableThousandsSeparator();
            }
        });
        otherThousandsSeparatorRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableThousandsSeparator();
            }
        });
        noneStringLimiterRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableStringLimiter();
            }
        });
        otherStringLimiterRB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableStringLimiter();
            }
        });
        trainingFileButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectTrainingFile();
            }
        });
        validationFileButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectValidationFile();
            }
        });
        testingFileButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                selectTestingFile();
            }
        });
        scanToEndCB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                enableLastLine();
            }
        });
        firstLineSpinnerModel.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                vetoFirstLine();
            }
        });
        lastLineSpinnerModel.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                vetoLastLine();
            }
        });

        enableDelimiter();
        enableTrainingForValidation();
        enableTrainingForTesting();
        enableLastLine();
        enableThousandsSeparator();
        enableStringLimiter();
    }

    protected void doOk() {
        ui.updateTrainingFiles(trainingFileNameField.getText(),
                useTrainingForValidationCB.isSelected(),
                validationFileNameField.getText(),
                validationPercentageSpinnerModel.getNumber().intValue(),
                useTrainingForTestingCB.isSelected(),
                testingFileNameField.getText(),
                testingPercentageSpinnerModel.getNumber().intValue(),
                firstLineSpinnerModel.getNumber().intValue(),
                scanToEndCB.isSelected(),
                lastLineSpinnerModel.getNumber().intValue(),
                spaceDelimitRB.isSelected(),
                tabDelimitRB.isSelected(),
                delimitField.getText(),
                decimalSeparatorField.getText(),
                otherThousandsSeparatorRB.isSelected(),
                thousandsSeparatorField.getText(),
                otherStringLimiterRB.isSelected(),
                stringLimiterField.getText(),
                randomizeDataCB.isSelected(),
                coalesceDuplicateColumnSeparatorsCB.isSelected());
        dispose();
    }

    private void enableDelimiter() {
        delimitField.setEnabled(otherDelimitRB.isSelected());
    }

    private void enableThousandsSeparator() {
        thousandsSeparatorField.setEditable(otherThousandsSeparatorRB.isSelected());
    }

    private void enableStringLimiter() {
        stringLimiterField.setEditable(otherStringLimiterRB.isSelected());
    }

    private void enableTrainingForValidation() {
        validationFileLabel.setEnabled(!useTrainingForValidationCB.isSelected());
        validationFileButton.setEnabled(!useTrainingForValidationCB.isSelected());
        validationFileNameField.setEnabled(!useTrainingForValidationCB.isSelected());
        validationPercentLabel.setEnabled(useTrainingForValidationCB.isSelected());
        validationPercentageSpinner.setEnabled(useTrainingForValidationCB.isSelected());
    }

    private void enableTrainingForTesting() {
        testingFileLabel.setEnabled(!useTrainingForTestingCB.isSelected());
        testingFileButton.setEnabled(!useTrainingForTestingCB.isSelected());
        testingFileNameField.setEnabled(!useTrainingForTestingCB.isSelected());
        testingPercentLabel.setEnabled(useTrainingForTestingCB.isSelected());
        testingPercentageSpinner.setEnabled(useTrainingForTestingCB.isSelected());
    }

    private void selectTrainingFile() {
        String selectedFileName = selectFile();
        if (selectedFileName != null) {
            trainingFileNameField.setText(selectedFileName);
        }
    }

    private void selectValidationFile() {
        String selectedFileName = selectFile();
        if (selectedFileName != null) {
            validationFileNameField.setText(selectedFileName);
        }
    }

    private void selectTestingFile() {
        String selectedFileName = selectFile();
        if (selectedFileName != null) {
            testingFileNameField.setText(selectedFileName);
        }
    }

    private String selectFile() {
        int i = chooser.showOpenDialog(this);
        if (i == JFileChooser.APPROVE_OPTION) {
            ((UI)getOwner()).storeDataDirectory(chooser);
            return chooser.getSelectedFile().getAbsolutePath();
        }
        return null;
    }

    private void enableLastLine() {
        lastLineSpinner.setEnabled(!scanToEndCB.isSelected());
        if (!scanToEndCB.isSelected()) {
            int firstLine = firstLineSpinnerModel.getNumber().intValue();
            int lastLine = lastLineSpinnerModel.getNumber().intValue();
            if (firstLine > lastLine) {
                lastLineSpinnerModel.setValue(firstLine);
            }
        }
    }

    private void vetoFirstLine() {
        if (scanToEndCB.isSelected()) {
            return;
        }
        int firstLine = firstLineSpinnerModel.getNumber().intValue();
        int lastLine = lastLineSpinnerModel.getNumber().intValue();
        if (firstLine > lastLine) {
            firstLineSpinnerModel.setValue(lastLine);
        }
    }

    private void vetoLastLine() {
        int firstLine = firstLineSpinnerModel.getNumber().intValue();
        int lastLine = lastLineSpinnerModel.getNumber().intValue();
        if (firstLine > lastLine) {
            lastLineSpinnerModel.setValue(firstLine);
        }
    }


}